package work.jame.dynamic.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.util.StringUtils;
import work.jame.dynamic.config.DynamicDataSourceConfig;

import java.sql.Driver;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author : Jame
 * @date : 2023-11-24 10:27
 **/
@Slf4j
public class RoutingDataSource extends AbstractRoutingDataSource {


    public RoutingDataSource(DynamicDataSourceConfig dynamicDataSourceConfig) {
        HashMap<Object, Object> routingDataSourceMap = parseConfig(dynamicDataSourceConfig);
        String defaultDataSourceKey = dynamicDataSourceConfig.getDefaultDataSourceKey();
        if (!routingDataSourceMap.containsKey(defaultDataSourceKey)) {
            log.error("默认数据源 [ " + defaultDataSourceKey + " ] 不存在");
            throw new RuntimeException("默认数据源 [ " + defaultDataSourceKey + " ] 不存在");
        }
        this.setTargetDataSources(routingDataSourceMap);
        this.setDefaultTargetDataSource(routingDataSourceMap.get(defaultDataSourceKey));
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicContextHolder.peek();
    }


    @Override
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        super.setTargetDataSources(targetDataSources);
    }


    @Override
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
    }

    private HashMap<Object, Object> parseConfig(DynamicDataSourceConfig config) {
        if (!StringUtils.hasText(config.getDefaultDataSourceKey())) {
            log.error("默认数据源不能为空字符串");
            throw new RuntimeException("默认数据源不能为空字符串");
        }
        Map<String, DataSourceProperties> map = config.getDataSources();
        if (map == null || map.size() == 0) {
            log.error("请指定数据源");
            throw new RuntimeException("请指定数据源");
        }
        HashMap<Object, Object> routingDataSourceMap = new HashMap<>();
        for (Map.Entry<String, DataSourceProperties> entry : map.entrySet()) {
            String dataSourceKey = entry.getKey();
            DataSourceProperties sourceProperties = entry.getValue();

            String driverClassName = sourceProperties.getDriverClassName();
            String url = sourceProperties.getUrl();
            String username = sourceProperties.getUsername();
            String password = sourceProperties.getPassword();

            if (!StringUtils.hasText(dataSourceKey)) {
                log.error("请指定数据源名称");
                throw new RuntimeException("请指定数据源名称");
            }
            if (!StringUtils.hasText(driverClassName)) {
                log.error("{}数据源未指定驱动", dataSourceKey);
                throw new RuntimeException(dataSourceKey + "数据源未指定驱动");
            }
            if (!StringUtils.hasText(url)) {
                log.error("{}数据源未指定url", dataSourceKey);
                throw new RuntimeException(dataSourceKey + "数据源未指定url");
            }
            if (!StringUtils.hasText(username)) {
                log.error("{}数据源未指定username", dataSourceKey);
                throw new RuntimeException(dataSourceKey + "数据源未指定username");
            }
            if (!StringUtils.hasText(password)) {
                log.error("{}数据源未指定password", dataSourceKey);
                throw new RuntimeException(dataSourceKey + "数据源未指定password");
            }
            Class<Driver> driverClass;
            try {
                driverClass = (Class<Driver>) Class.forName(driverClassName);
            } catch (ClassNotFoundException e) {
                log.error(e.getMessage(), e);
                throw new RuntimeException(e);
            }
            try {
                SimpleDriverDataSource source = new SimpleDriverDataSource(
                        driverClass.newInstance(),
                        url,
                        username,
                        password);
                routingDataSourceMap.put(dataSourceKey, source);
            } catch (InstantiationException | IllegalAccessException e) {
                log.error(e.getMessage(), e);
                throw new RuntimeException(e);
            }
        }
        return routingDataSourceMap;
    }


}
